package utils

import (
	"encoding/json"
	"reflect"
)

/*
实现深拷贝
*/

func CopyPtr[T any](v *T) *T {
	if v == nil {
		return v
	}
	s := *v
	return &s
}

func CopySlice[T any](v []T) []T {
	res := make([]T, len(v))
	copy(res, v)
	return res
}

func CopyPtrSlice[T any](v []*T) []*T {
	res := make([]*T, len(v))
	for index, elem := range v {
		s := *elem
		res[index] = &s
	}
	return res
}

type Copyable[T any] interface {
	Copy() T
}

func CopyInterfaceSlice[T Copyable[T]](v []T) []T {
	res := make([]T, len(v))
	for index, elem := range v {
		res[index] = elem.Copy()
	}
	return res
}

func CopySliceByReflect[T any](v []T) []T {
	inf := reflect.TypeOf((*Copyable[T])(nil)).Elem()
	res := make([]T, len(v))
	if typ := reflect.TypeOf(v).Elem(); typ.Implements(inf) {
		for index, elem := range v {
			res[index] = reflect.ValueOf(elem).MethodByName("Copy").Call(nil)[0].Interface().(T)
		}
	} else if typ.Kind() == reflect.Ptr {
		elemType := typ.Elem()
		for index, elem := range v {
			s := reflect.New(elemType)
			s.Elem().Set(reflect.ValueOf(elem).Elem())
			reflect.ValueOf(res).Index(index).Set(s)
		}
	} else {
		copy(res, v)
	}
	return res
}

func Copy[T any](v T) T {
	bytes, _ := json.Marshal(v)
	var v2 T
	_ = json.Unmarshal(bytes, &v2)
	return v2
}
